package com.linkoog.devtools.archive.filesystem.gz;

import com.linkoog.devtools.archive.filesystem.ArchiveHandlerBase;
import com.linkoog.devtools.archive.filesystem.ArchiveFile;
import com.linkoog.devtools.archive.filesystem.tar.TarGzFile;
import com.linkoog.devtools.archive.filesystem.tar.TarGzFileType;
import com.linkoog.devtools.archive.util.ArchiveUtils;
import com.linkoog.devtools.archive.util.CoreUtil;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 */
public class GZFile implements ArchiveFile {

    private final File _file;

    private String _innerName;

    private BufferedInputStream _inputStream;

    private GzipCompressorInputStream _gZIPInputStream;

    private TarGzFile _tarGzFile;

    /**
     * If it's a tar with gz based file, delegate to {@link TarGzFile} to handle all
     */
    public GZFile(File file) {
        _file = file;

        String fileName = _file.getName();
        if (fileName.endsWith(".tar.gz") || fileName.endsWith(CoreUtil.DOT + TarGzFileType.INSTANCE.getDefaultExtension())) {
            _tarGzFile = new TarGzFile(_file);
        }
    }

    @Override
    public Map<String, ArchiveHandlerBase.EntryInfo> createEntriesInfoMap() throws IOException {
        if (_tarGzFile != null) {
            return _tarGzFile.createEntriesInfoMap();
        }

        try (GzipCompressorInputStream inputStream = (GzipCompressorInputStream)getInputStream()){
            _innerName = inputStream.getMetaData().getFilename();
        }

        if (_innerName == null) {
            int idx = _file.getName().indexOf(CoreUtil.DOT + GZFileType.INSTANCE.getDefaultExtension());
            _innerName = idx == -1 ? "contents" : _file.getName().substring(0, idx);
        }

        ArchiveHandlerBase.EntryInfo root = ArchiveUtils.createRootEntry();
        Map<String, ArchiveHandlerBase.EntryInfo> entries = new HashMap();
        entries.put("", root);
        entries.put(_innerName, new ArchiveHandlerBase.EntryInfo(_innerName, false, _file.length(), _file.lastModified(), root));
        return entries;
    }

    @Override
    public byte[] getEntryBytes(String relativePath) throws IOException {
        if (_tarGzFile != null) {
            return _tarGzFile.getEntryBytes(relativePath);
        }

        try (InputStream inputStream = getInputStream()){
            return inputStream.readAllBytes();
        }
    }

    @Override
    public InputStream getInputStream() throws IOException {
        if (_tarGzFile != null) {
            return _tarGzFile.getInputStream();
        }

        _inputStream = new BufferedInputStream(new FileInputStream(_file));
        return _gZIPInputStream = new GzipCompressorInputStream(_inputStream);
    }

    @Override
    public void close() throws IOException {
        if (_gZIPInputStream != null) _gZIPInputStream.close();
        if (_inputStream != null) _inputStream.close();
    }

}